package com.creator.pangu.core.security.filter;

import cn.hutool.core.util.StrUtil;
import com.creator.pangu.base.entity.SysUser;
import com.creator.pangu.base.service.ISysUserRoleService;
import com.creator.pangu.core.security.dto.LoginUser;
import com.creator.pangu.core.security.service.UserDetailsServiceImpl;
import com.creator.pangu.core.security.util.JWTUtil;
import com.creator.pangu.core.security.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class JWTAuthenticationFilter extends OncePerRequestFilter {

    @Resource
    private JWTUtil jwtUtil;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        /**
         * 整理代码逻辑，封装JWTUtil类，完成签发、验证、续签等功能
         * 此处拦截器考虑处理逻辑
         * 1、request对象传入JWTUtil中，获取当前登录用户信息。
         * 2、登录用户信息是否为空，上下文转给你是否有已经登录信息。
         * 3、验证token
         * 4、将验证信息添加上下文。
         */

        // 请求中获取token信息
        String token = jwtUtil.getTokenByRequest(request);

        // token中解析到用户名
        String loginName = jwtUtil.getUserNameByToken(token);

        LoginUser loginUser = null;

        //判断当前上下文是否已经登录
        if (StrUtil.isNotEmpty(loginName) && SecurityContextHolder.getContext().getAuthentication() == null) {

            // 缓存中获取登录用户和权限信息，进入缓存的登录用户包含权限信息集合
            loginUser  = redisUtil.getCacheObject(loginName);
            // 缓存中没有，查询数据库，防止缓存数据丢失
            if(null == loginUser) {
                loginUser = (LoginUser) userDetailsService.loadUserByUsername(loginName);
            }
            if(loginUser != null && jwtUtil.verify(token, loginUser.getUsername())){
                // 组装authentication对象，构造参数是Principal Credentials 与 Authorities
                // 后面的拦截器里面会用到 grantedAuthorities 方法
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginName, null, loginUser.getAuthorities());

                // 将authentication信息放入到上下文对象中
                SecurityContextHolder.getContext().setAuthentication(authentication);

                log.info("JWT过滤器通过校验请求头token自动登录成功, user : {}", loginUser.getUsername());
            }
        }

        filterChain.doFilter(request, response);

    }
}
